﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AsyncAwaitDemo.ClassLibrary
{
    /// <summary>
    /// 这个是高级进阶第17期里面的async 以及await的demo
    /// </summary>
    public class AwaitAsyncClass
    {
        public static void TestShow()
        {
            Console.WriteLine($"TestShow  start 执行~~  当前主线程id={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
            Test(); 
            Console.WriteLine($"TestShow  end   执行~~  当前主线程id={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
        }

        /// <summary>
        /// 如果函数使用了async  如果函数没有返回值，需要指定返回task
        /// </summary>
        public static void Test()
        {
            Console.WriteLine($"当前主线程id={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
            {
               NoReturnNoAwait();
            }

            {
                //Task t = NoReturn();
                //t.Wait();//主线程在这里就会卡顿，等待t执行完成；
                //{
                //    for (int i = 0; i < 10; i++)
                //    {
                //        Thread.Sleep(300);
                //        Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")} i={i}");
                //    }
                //}
            }

            {
                //Task t = NoReturnTask();
                //Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                //t.Wait();//主线程等待Task的完成  阻塞的
                //t.Wait();
                //await t;//await后的代码会由线程池的线程执行  非阻塞
            }

            {
                //Task<long> t = SumAsync();
                //Console.WriteLine($"1---Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId} Time={DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");


                // long lResult = t.Result;//访问result,阻塞式   主线程等待所有的任务完成 //如果访问Result，就相当于是同步方法！
                // t.Wait();//等价于上一行,阻塞式--同步

                //t.Result; 
                //await t;//非阻塞，
            }

            #region MyRegion  
            //{
            //    Task<int> t = SumFactory();
            //    Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            //    long lResult = t.Result;//没有await和async 普通的task
            //    t.Wait();
            //}
            //Console.WriteLine($"Test Sleep Start {Thread.CurrentThread.ManagedThreadId}");
            //Thread.Sleep(10000);
            //Console.WriteLine($"Test Sleep End {Thread.CurrentThread.ManagedThreadId}");
            #endregion



            Console.WriteLine($"2---Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId} Time={DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}"); //主线程执行的；

            //Console.Read();
        }


        /// <summary>
        /// 只有async没有await
        /// 跟普通方法没有区别
        /// </summary>
        private static async void NoReturnNoAwait()
        {
            //主线程执行
            Task task = Task.Run(() =>//启动新线程完成任务
            {
                Thread.Sleep(1000);
                Console.WriteLine($"NoReturnNoAwait Sleep3000 before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(1000);
                Console.WriteLine($"NoReturnNoAwait Sleep3000 after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
            });

            //主线程执行
            Console.WriteLine($"NoReturnNoAwait Sleep after Task,ThreadId={Thread.CurrentThread.ManagedThreadId}");
        }

        /// <summary>
        /// 1.主线程和子线程是并发执行
        /// 2.有点类似于一个回调
        /// 3.有async/await 如果没有返回值，就直接返回一个Task
        /// 4.在前面如果wait 等待，前面的主线程会直接往后，和当前这个函数执行的内容同步执行；
        /// </summary>
        private static async Task NoReturn()
        {
            //主线程执行
            Console.WriteLine($"NoReturn Sleep before await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
            TaskFactory taskFactory = new TaskFactory();
            Task task = taskFactory.StartNew(() =>
            {
                Console.WriteLine($"NoReturn Sleep3000 before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(3000);
                Console.WriteLine($"NoReturn Sleep3000 after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
            });

            //像什么？continuwith

            //task.ContinueWith(t =>
            //{
            //    Console.WriteLine($"NoReturn Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
            //});

            //return task;
            //主线程到await这里就返回了，执行主线程任务 ,task中的任务执行完毕以后---继续执行await后面的后续内容，有可能是子线程，也有可能是其他线程，甚至有可能是主线程来执行；


            //  Console.WriteLine($"NoReturn Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
        }

        /// <summary>
        /// 无返回值  async Task == async void
        /// 建议大家如果没有返回值的，就可以返回一个tasks
        /// Task和Task<T>能够使用await, Task.WhenAny, Task.WhenAll等方式组合使用。Async Void 不行
        /// 
        /// 
        /// 效果：
        /// 尽管启动了线程，但是代码是按照顺序执行的； 
        /// Why???   await 修饰后的特点；
        /// 
        /// 主线程调用有async  await 修饰的函数； 主线程如果遇到await了，主线程就直接回去了；然后继续执行当前函数调用的后面的代码、且后面这个逻辑的执行和启动的子线程的逻辑执行是同步执行的；
        /// </summary>
        /// <returns></returns>
        private static async Task NoReturnTask() //在async/await方法里面如果没有返回值，默认返回一个Task
        {
            //这里还是主线程的id
            Console.WriteLine($"NoReturnTask Sleep before await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
            Task task = Task.Run(() =>   //启动了一个线程
            {
                Console.WriteLine($"NoReturnTask Sleep3000 before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(1000);
                Console.WriteLine($"NoReturnTask Sleep3000 after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
            });
            await task;
            Console.WriteLine($"NoReturnTask Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
            //return;
            //return new TaskFactory().StartNew(() => { });  //不能return  没有async才行
        }

        /// <summary>
        /// 带返回值的Task  
        /// 要使用返回值就一定要等子线程计算完毕
        /// 
        /// 1.await: 线程遇到awai就返回，不阻塞：并发执行----多线程就要并发执行；
        /// 2.做到控制顺序  
        /// 其实就是以写同步方法 的方式;来完成多线程：--可以控制顺序
        /// 
        /// 做到了：以同步编程的思想，来做异步编程；
        /// 像回调；
        /// 
        /// </summary>
        /// <returns>async 就只返回long</returns>
        private static async Task<long> SumAsync()
        {
            #region 这两个启动的线程是不能控制顺序的 
            //Task.Run(() => { }); 
            //Task.Run(() => { });
            #endregion


            Console.WriteLine($"SumAsync 0000 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            long result = 0;

            #region 回调
            await Task.Run(() =>
            {
                for (int k = 0; k < 10; k++)
                {
                    Console.WriteLine($"SumAsync 0000  {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId} Time={DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
                    Thread.Sleep(1000);
                }
                for (long i = 0; i < 999_999_999; i++)
                {
                    result += i;
                }
            }); 

            Console.WriteLine($"SumAsync 1111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId} Time={DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");

            await Task.Run(() =>
            {
                for (int k = 0; k < 10; k++)
                {
                    Console.WriteLine($"SumAsync 1111  {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId} Time={DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
                    Thread.Sleep(1000);
                }
                for (long i = 0; i < 999_999_999; i++)
                {
                    result += i;
                }
            });
            // Task.Run(() =>
            //{
            //    for (int k = 0; k < 10; k++)
            //    {
            //        Console.WriteLine($"SumAsync 0000  {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            //        Thread.Sleep(1000);
            //    }
            //    for (long i = 0; i < 999_999_999; i++)
            //    {
            //        result += i;
            //    }
            //}).ContinueWith(t =>
            //{
            //    Console.WriteLine($"SumFactory 1111   end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            //    for (int k = 0; k < 10; k++)
            //    {
            //        Console.WriteLine($"SumAsync  1111 {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            //        Thread.Sleep(1000);
            //    }
            //    for (long i = 0; i < 999999999; i++)
            //    {
            //        result += i;
            //    }
            //}).ContinueWith(t => {
            //    for (int k = 0; k < 10; k++)
            //    {
            //        Console.WriteLine($"SumAsync 2222 {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            //        Thread.Sleep(1000);
            //    }

            //    for (long i = 0; i < 999999999; i++)
            //    {
            //        result += i;
            //    }
            //});   
            #endregion

            //await Task.Run(() =>
            //{
            //    for (int k = 0; k < 10; k++)
            //    {
            //        Console.WriteLine($"SumAsync 0000  {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            //        Thread.Sleep(1000);
            //    }
            //    for (long i = 0; i < 999_999_999; i++)
            //    {
            //        result += i;
            //    }
            //});

            //Console.WriteLine($"SumFactory 1111   end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");

            //await Task.Run(() =>
            //{
            //    for (int k = 0; k < 10; k++)
            //    {
            //        Console.WriteLine($"SumAsync  1111 {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            //        Thread.Sleep(1000);
            //    }
            //    for (long i = 0; i < 999999999; i++)
            //    {
            //        result += i;
            //    }
            //});
            //Console.WriteLine($"SumFactory 2222   end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");

            //await Task.Run(() =>
            //{
            //    for (int k = 0; k < 10; k++)
            //    {
            //        Console.WriteLine($"SumAsync 2222 {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            //        Thread.Sleep(1000);
            //    }

            //    for (long i = 0; i < 999999999; i++)
            //    {
            //        result += i;
            //    }
            //});
            Console.WriteLine($"SumFactory 3333   end ManagedThreadId={Thread.CurrentThread.ManagedThreadId} Time={DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");

            return result;
        }


        /// <summary>
        /// 真的返回Task  不是async  
        /// 
        /// 要使用返回值就一定要等子线程计算完毕
        /// </summary>
        /// <returns>没有async Task</returns>
        private static Task<int> SumFactory()
        {
            Console.WriteLine($"SumFactory 111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            TaskFactory taskFactory = new TaskFactory();
            Task<int> iResult = taskFactory.StartNew<int>(() =>
            {
                Thread.Sleep(3000);
                Console.WriteLine($"SumFactory 123 Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                return 123;
            }).ContinueWith(c =>
            {

                Thread.Sleep(3000);
                Console.WriteLine($"SumFactory 234 Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                return 123;

            }).ContinueWith(t =>
            {

                Thread.Sleep(3000);
                Console.WriteLine($"SumFactory 345 Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                return 123;
            });


            //就是回调来控制线程内部的业务逻辑的执行顺序---不爽

            //Console.WriteLine($"This is {iResult.Result}");
            Console.WriteLine($"SumFactory 111   end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            return iResult;
        }

        #region foreach await


        #region 论证结果：

        private static async Task Show1()
        {
            Console.WriteLine($"Show1 执行 Start~~ ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            await Task.Run(() =>
            {
                Console.WriteLine($"Show1启动线程1111111111111111~~ ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(5000);
                Console.WriteLine($"Show1启动线程1111111111111111~~ ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            });
            await Show2();
            Console.WriteLine($"Show1 执行 End~~ ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
        }


        private static async Task Show2()
        {
            Console.WriteLine($"Show2 执行 Start~~ ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            await Task.Run(() =>
            {
                Console.WriteLine($"Show2启动线程2222222222222~~ ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(2000);
                Console.WriteLine($"Show2启动线程2222222222222~~ ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            });
            await Show3();
            Console.WriteLine($"Show2 执行 End~~ ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
        }


        private static async Task Show3()
        {
            Console.WriteLine($"Show3 执行 Start~~ ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            await Task.Run(() =>
            {
                Console.WriteLine($"Show3启动线程3333333333333333~~ ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
                Thread.Sleep(2000);
                Console.WriteLine($"Show3启动线程33333333333333333~~ ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            });
            Console.WriteLine($"Show3 执行 End~~ ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
        }

        #endregion



        //C#8.0之后
        private async Task Test8()
        {
            await foreach (var i in this.GenerateSequence())
            {
                Console.WriteLine($"this is {i} foreach await");
            }
        }

        public async IAsyncEnumerable<int> GenerateSequence()
        {
            for (int i = 0; i < 20; i++)
            {
                await Task.Delay(100);
                yield return i;
            }
        }
        #endregion
    }
}
